package com.base.cn.platform.os.common.log.aop;

import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.common.utils.web.LoginUtil;
import com.base.cn.platform.os.common.utils.web.WebUtils;
import com.base.cn.platform.os.service.manage.log.OpLogService;
import com.google.common.collect.Maps;
import javassist.NotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;

/**
 * 文 件 名:OpLogAop
 * 创 建 人:hackeridear
 * 创建日期:2018-12-06
 * 描   述:OpLogAop
 * 修 改 人:
 * 修改日期:
 * 版 本 号:v 1.0.0
 */
@Slf4j
@Component
@Aspect
public class OpLogAop {

    @Autowired
    public LoginUtil loginUtil;
    @Autowired
    public OpLogService opLogService;

    private static ThreadLocal<Long> runTime = ThreadLocal.withInitial(() -> 0L);

    @PostConstruct
    public void init(){
        log.info("-----------------------------");
    }

    @Pointcut("@annotation(com.base.cn.platform.os.common.log.aop.OpLog)")
    public void pointCutMethod(){}

    @Before("pointCutMethod()")
    public void doBefore(JoinPoint joinPoint){
        log.info("opLog前置通知========================");
    }

    @After("@annotation(opLog)")
    public void doAfter(JoinPoint point,OpLog opLog) throws NotFoundException {
        log.info("opLog后置通知========================");
        Map<String,Object> paramsMap = Maps.newHashMap();
        String className = point.getTarget().getClass().getName();
        String methodName = point.getSignature().getName();
        String action;
        String module;
        String account="";
        if(methodName.equals("gotoLogin")) {
            action = AnnotationUtils.get().getAnnotatioinFieldValue(className, methodName, OpLog.class.getName(), "action", String.class);
            module = AnnotationUtils.get().getAnnotatioinFieldValue(className, methodName, OpLog.class.getName(), "module", AdminModuleEnum.class);
            account = AnnotationUtils.get().getAnnotatioinFieldValue(className, methodName, OpLog.class.getName(), "account", String.class);
        }else{
            action = opLog.action();
            module = opLog.module().name();
        }
        HttpServletRequest request = WebUtils.getRequest();
        final String url = request.getRequestURL().toString();
        final String requestMethod = request.getMethod();
        final String ip = WebUtils.getIpAddr(request);
        if(StringUtils.isEmpty(account))
            account = loginUtil.getLoginUserName(request);
        final Object[] args = point.getArgs();
        final String params = Arrays.toString(args);
        paramsMap.put("url", url);
        paramsMap.put("requestMethod", requestMethod);
        if(ObjectUtils.isEmpty(account)){
            paramsMap.put("account",request.getParameter("userName"));
        }else{
            paramsMap.put("account",account);
        }
        paramsMap.put("params", params);
        paramsMap.put("ip", ip);
        paramsMap.put("module",module);
        paramsMap.put("action", action);
        paramsMap.put("runTime", runTime.get());
        // 保存日志
        opLogService.saveOpLog(paramsMap);
    }

    @AfterReturning("pointCutMethod()")
    public void doAfterReturn(JoinPoint joinPoint){
        log.info("opLog返回通知========================");
    }

    @Around("pointCutMethod()")
    public Object recordOperateLog(ProceedingJoinPoint point) {
        Object result = null;
        long beginTime = System.currentTimeMillis();
        try {
            // 执行方法
            result = point.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        runTime.set(time);
        return result;
    }
}
